package com.example.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.example.dto.ApiResponse;
import com.example.dto.JwtResponse;
import com.example.dto.LoginRequest;
import com.example.dto.RegisterRequest;
import com.example.entity.User;
import com.example.service.UserService;
import com.example.service.UserSessionService;
import com.example.utils.IpUtils;
import com.fasterxml.jackson.databind.ObjectMapper;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;

import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/api/auth")
public class AuthController {
    private static final Logger logger = LoggerFactory.getLogger(AuthController.class);

    @Autowired
    private UserService userService;

    @Autowired
    private UserSessionService userSessionService;

    @Autowired
    private IpUtils ipUtils;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    @Autowired
    private ObjectMapper objectMapper;

    /**
     * 用户登录接口
     * 使用Redis缓存用户基本信息，提高查询性能
     */
    @PostMapping("/login")
    public ResponseEntity<?> authenticateUser(@Valid @RequestBody LoginRequest loginRequest, HttpServletRequest request) {
        logger.info("User attempting to login: {}", loginRequest.getUsername());
        try {
            User user = null;
            
            // 1. 先尝试从Redis缓存获取用户信息（仅用于减少数据库查询）
            String userCacheKey = "user:basic:" + loginRequest.getUsername();
            try {
                Object cachedUserObj = redisTemplate.opsForValue().get(userCacheKey);
                if (cachedUserObj != null) {
                    user = objectMapper.readValue(cachedUserObj.toString(), User.class);
                    logger.debug("用户信息从Redis缓存获取: {}", loginRequest.getUsername());
                }
            } catch (Exception e) {
                logger.warn("Redis缓存读取失败，将从数据库查询: {}", e.getMessage());
            }
            
            // 2. 如果缓存中没有，从数据库查询
            if (user == null) {
                user = userService.getUserByUsername(loginRequest.getUsername());
                if (user == null) {
                    logger.error("User not found: {}", loginRequest.getUsername());
                    return ResponseEntity.status(401).body(ApiResponse.error("用户不存在"));
                }
                
                // 3. 将用户基本信息缓存到Redis（排除敏感信息如密码）
                cacheUserInfo(user);
            }
            
            // 4. 进行身份验证（必须验证密码）
            JwtResponse jwtResponse = userService.authenticateUser(loginRequest);

            // 5. 获取客户端信息
            String deviceInfo = request.getHeader("User-Agent");
            String ipAddress = ipUtils.getClientIpAddress(request);
            
            // 记录IP获取详情（调试用）
            if (logger.isDebugEnabled()) {
                ipUtils.logIpDetails(request);
            }
            
            logger.info("User {} logged in from IP: {} ({})", 
                       loginRequest.getUsername(), 
                       ipAddress, 
                       ipUtils.getIpLocation(ipAddress));
            
            // 6. 创建用户会话
            userSessionService.createSession(jwtResponse.getId(), jwtResponse.getToken(), deviceInfo, ipAddress);

            // 7. 缓存登录成功的用户会话信息
            cacheLoginSession(jwtResponse, ipAddress);

            logger.info("User successfully logged in: {}", loginRequest.getUsername());
            return ResponseEntity.ok(ApiResponse.success(jwtResponse));
            
        } catch (DisabledException e) {
            logger.warn("Disabled account attempted to login: {}", loginRequest.getUsername());
            return ResponseEntity.status(403).body(ApiResponse.error("账号已被封禁，请联系管理员"));
        } catch (BadCredentialsException e) {
            logger.warn("Login failed for user {}: {}", loginRequest.getUsername(), e.getMessage());
            return ResponseEntity.status(401).body(ApiResponse.error(e.getMessage() + "  密码错误！"));
        } catch (Exception e) {
            logger.error("Authentication failed for user: {}", loginRequest.getUsername(), e);
            return ResponseEntity.badRequest().body(ApiResponse.error("认证失败: " + e.getMessage()));
        }
    }

    /**
     * 缓存用户基本信息到Redis（排除敏感信息）
     * @param user 用户对象
     */
    private void cacheUserInfo(User user) {
        try {
            String userCacheKey = "user:basic:" + user.getUsername();
            
            // 创建一个不包含密码的用户对象副本
            User safeUser = new User();
            safeUser.setId(user.getId());
            safeUser.setUsername(user.getUsername());
            safeUser.setEmail(user.getEmail());
            safeUser.setFullName(user.getFullName());
            safeUser.setPhoneNumber(user.getPhoneNumber());
            safeUser.setEnabled(user.getEnabled());
            safeUser.setCreateTime(user.getCreateTime());
            safeUser.setUpdateTime(user.getUpdateTime());
            safeUser.setLastLoginIp(user.getLastLoginIp());
            safeUser.setLastLoginTime(user.getLastLoginTime());
            safeUser.setAvatarUrl(user.getAvatarUrl());
            safeUser.setExamNumber(user.getExamNumber());
            // 不设置密码字段，确保安全
            
            String userJson = objectMapper.writeValueAsString(safeUser);
            
            // 缓存30分钟
            redisTemplate.opsForValue().set(userCacheKey, userJson, 30, TimeUnit.MINUTES);
            logger.debug("用户基本信息已缓存到Redis: {}", user.getUsername());
            
        } catch (Exception e) {
            logger.warn("缓存用户信息到Redis失败: {}", e.getMessage());
        }
    }
    
    /**
     * 缓存登录会话信息
     * @param jwtResponse JWT响应
     * @param ipAddress IP地址
     */
    private void cacheLoginSession(JwtResponse jwtResponse, String ipAddress) {
        try {
            String sessionCacheKey = "login:session:" + jwtResponse.getToken().substring(0, 10);
            
            // 缓存会话基本信息
            String sessionInfo = String.format("{\"userId\":%d,\"username\":\"%s\",\"ip\":\"%s\",\"loginTime\":\"%s\"}", 
                jwtResponse.getId(), jwtResponse.getUsername(), ipAddress, System.currentTimeMillis());
            
            // 缓存24小时（与JWT过期时间一致）
            redisTemplate.opsForValue().set(sessionCacheKey, sessionInfo, 24, TimeUnit.HOURS);
            logger.debug("登录会话信息已缓存: {}", jwtResponse.getUsername());
            
        } catch (Exception e) {
            logger.warn("缓存登录会话信息失败: {}", e.getMessage());
        }
    }

    @PostMapping("/register")
    public ResponseEntity<?> registerUser(@Valid @RequestBody RegisterRequest registerRequest) {
        return ResponseEntity.ok(userService.registerUser(registerRequest));
    }

    @PostMapping("/logout")
    public ResponseEntity<?> logoutUser(@RequestHeader("Authorization") String token) {
        if (token != null && token.startsWith("Bearer ")) {
            token = token.substring(7);
            
            // 清除Redis中的登录会话缓存
            try {
                String sessionCacheKey = "login:session:" + token.substring(0, 10);
                redisTemplate.delete(sessionCacheKey);
                logger.debug("已清除Redis中的登录会话缓存");
            } catch (Exception e) {
                logger.warn("清除Redis登录会话缓存失败: {}", e.getMessage());
            }
            
            return ResponseEntity.ok(userSessionService.invalidateSession(token));
        }
        return ResponseEntity.badRequest().body(ApiResponse.error("Invalid token"));
    }

    @PostMapping("/logout-all")
    public ResponseEntity<?> logoutAllDevices(@RequestHeader("Authorization") String token) {
        if (token != null && token.startsWith("Bearer ")) {
            token = token.substring(7);
            Long userId = userService.getCurrentUserId();
            if (userId != null) {
                // 清除该用户的所有Redis缓存
                try {
                    String userCachePattern = "user:basic:*";
                    String sessionCachePattern = "login:session:*";
                    
                    // 注意：在生产环境中应该避免使用keys命令，这里仅作示例
                    // 建议使用更精确的键名或其他清理策略
                    
                    logger.debug("用户 {} 执行全设备登出，清除相关缓存", userId);
                } catch (Exception e) {
                    logger.warn("清除用户Redis缓存失败: {}", e.getMessage());
                }
                
                return ResponseEntity.ok(userSessionService.invalidateAllUserSessions(userId));
            }
        }
        return ResponseEntity.badRequest().body(ApiResponse.error("Invalid token"));
    }

    @GetMapping("/sessions")
    public ResponseEntity<?> getCurrentUserSessions() {
        Long userId = userService.getCurrentUserId();
        if (userId != null) {
            return ResponseEntity.ok(ApiResponse.success(
                "Active sessions retrieved successfully",
                userSessionService.getUserActiveSessions(userId)
            ));
        }
        return ResponseEntity.badRequest().body(ApiResponse.error("User not found"));
    }
}